package drds.plus.sql_process.optimizer.execute_plan_optimizer;

import drds.plus.common.jdbc.Parameters;
import drds.plus.common.thread_local.ThreadLocalMap;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Query;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryWithIndex;

import java.util.Map;

/**
 * 添加下last sequence value
 */
public class FillLastSequenceValueOptimizer implements ExecutePlanOptimizer {

    public ExecutePlan optimize(ExecutePlan executePlan, Parameters parameters, Map<String, Object> extraCmd) {
        if (executePlan instanceof Query) {
            fillFromRoot(executePlan);
        } else {
            executePlan.setLastSequenceValue(getLastSequneceValue(executePlan));
        }
        return executePlan;
    }

    public void fillFromRoot(ExecutePlan executePlan) {
        executePlan.setLastSequenceValue(getLastSequneceValue(executePlan));
        if (executePlan instanceof MergeQuery) {
            for (ExecutePlan subExecutePlan : ((MergeQuery) executePlan).getExecutePlanList()) {
                fillFromRoot(subExecutePlan);
            }
        } else if (executePlan instanceof QueryWithIndex && ((QueryWithIndex) executePlan).getSubQuery() != null) {
            fillFromRoot(((QueryWithIndex) executePlan).getSubQuery());
        } else if (executePlan instanceof Join) {
            fillFromRoot(((Join) executePlan).getLeftNode());
            fillFromRoot(((Join) executePlan).getRightNode());
        } else {
            executePlan.setLastSequenceValue(getLastSequneceValue(executePlan));
        }
    }

    private Long getLastSequneceValue(ExecutePlan executePlan) {
        if (executePlan.isExistSequenceValue()) {
            return (Long) ThreadLocalMap.get(ExecutePlan.LAST_SEQUENCE_VALUE);
        } else {
            return null;
        }
    }

}
